<?php
// +-----------------+------------------------------------------+------+-----+---------+----------------+
// | Field           | Type                                     | Null | Key | Default | Extra          |
// +-----------------+------------------------------------------+------+-----+---------+----------------+
// | id              | int(11)                                  | NO   | PRI | NULL    | auto_increment |
// | name            | varchar(50)                              | NO   |     |         |                |
// | password        | varchar(64)                              | NO   |     |         |                |
// | nickname        | varchar(50)                              | YES  |     |         |                |
// | mobile          | varchar(15)                              | YES  | MUL |         |                |
// | email           | varchar(100)                             | YES  |     |         |                |
// | url             | varchar(255)                             | YES  |     |         |                |
// | avatar          | varchar(255)                             | YES  |     |         |                |
// | gender          | enum('secret','male','female','unknown') | YES  |     | secret  |                |
// | birthday        | date                                     | YES  |     | NULL    |                |
// | signature       | varchar(40)                              | YES  |     |         |                |
// | last_login_ip   | bigint(20) unsigned                      | YES  |     | 0       |                |
// | last_login_time | int(11) unsigned                         | YES  |     | 0       |                |
// | activation_key  | varchar(60)                              | YES  |     |         |                |
// | status          | tinyint(1)                               | YES  |     | 1       |                |
// | member_id       | int(11) unsigned                         | YES  |     | 0       |                |
// | create_time     | int(11) unsigned                         | YES  |     | 0       |                |
// | update_time     | int(11) unsigned                         | YES  |     | 0       |                |
// | delete_time     | int(11) unsigned                         | YES  |     | 0       |                |
// | college_name    | varchar(50)                              | YES  |     |         |                |
// | pro_title       | varchar(30)                              | YES  |     |         |                |
// +-----------------+------------------------------------------+------+-----+---------+----------------+
namespace app\common\model;

use think\facade\Config;
use think\facade\Session;
use app\common\model\Base;
use app\common\validate\User as Validate;
class User extends Base
{
    /**
     * 与Member BelongsTo关联设置
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-07
     * @return   array              [description]
     */
    public function member()
    {
        return $this->belongsTo('Member', 'member_id');
    }

    /**
     * 搜索方法
     * @Author   Laifuzi
     * @DateTime 2018-06-06
     * @param    array      $param     查询参数
     * @param    integer    $page_rows 每页显示数量
     * @return   Paginate              分页查询结果
     */
    function minePaginate($param, $page_rows = 0)
    {
        if($page_rows < 1){
            $page_rows = Config::get('paginate.list_rows');
        }

        $map = $this->parseSearchParam($param);

        $config = [];
        $config["query"] = $param;
        // 分页参数名是 page ，paginate方法内有获取到该值的方法
        $page = 1;
        if(isset($param["page"])){
            $page = intval($param["page"]);
        }
        $config["page"] = $page;

        $select_fields = [
            'id', 'name', 'mobile', 'email', 'status', 'create_time',
            "IF(last_login_ip!='' && last_login_ip>0, INET_NTOA(last_login_ip), '') AS last_ip",
            "FROM_UNIXTIME(last_login_time, '%Y-%m-%d %H:%i') AS last_login_time",
        ];

        $order_type = '';
        if(isset($param['order'])){
            $order_type = $param['order'];
        }
        $order_str = $this->queryOrderStr($order_type);

        $paginate = $this->field($select_fields)->where($map)->order($order_str)->paginate($page_rows, false, $config);
        return $paginate;
    }

    /**
     * 导出申报项目记录
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-21
     * @param    [type]             $param [description]
     * @return   [type]                    [description]
     */
    public function exportExcel($param)
    {
        $date_str = date('Y-m-d', time());
        $objPHPExcel = new \PHPExcel();
        $objPHPExcel->getProperties()
                     ->setCreator('laifuzi') //设置创建者
                     ->setLastModifiedBy($date_str) //设置时间
                     ->setTitle('报名信息'); //设置类别

        $activeSheet = $objPHPExcel->getActiveSheet();
        $activeSheet->setTitle("报名信息");

        // 设置导出Excel的标题
        $headers = $this->exportHeaders();
        $row_idx = 1;
        foreach ($headers as $col_idx => $header) {
          $activeSheet->setCellValueByColumnAndRow($col_idx, $row_idx, $header['title']);
        }

        $page = 1;
        $per_page = 100; // 每次查询数量
        while(true){
            $param['page'] = $page++;
            $res = $this->minePaginate($param, $per_page);
            $list = $res->all();
            foreach ($list as $key => $item) {
                $row_idx++;
                $col_idx = 0;
                foreach ($headers as $col_idx => $header) {
                    $name = $header['name'];
                    $cell_value = $item[$name];
                    if(empty($cell_value) && isset($header['default'])){
                        $cell_value = $header['default'];
                    }
                    switch ($name) {
                    case 'status':
                        $cell_value = get_field_text('user_status', $cell_value);
                        break;
                    case 'last_login_time':
                        $cell_value = format_show_time($cell_value);
                        break;
                    }
                    $activeSheet->setCellValueByColumnAndRow($col_idx, $row_idx, $cell_value);
                }
            }

            // 已经到最后一页
            if($page >= $res->lastPage()){
                break;
            }
        }

        header('Content-Type: application/vnd.ms-excel');
        header('Content-Disposition: attachment;filename="user_'.date("mdH").'.xls"');
        header('Cache-Control: max-age=0');
        $objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
        $objWriter->save('php://output');
    }

    /**
     * 用户注册
     * @Author   Laifuzi
     * @DateTime 2018-06-06
     * @param    array     $data 用户数据
     * @return   array
     */
    public function createItem($data)
    {
        $res = ['status' => false, 'data' => [], 'msg' => "注册失败"];

        $validate = new Validate;
        if(!$validate->scene('create')->check($data)){
            $res['msg'] = $validate->getError();
            return $res;
        }

        $data['password'] = $this->md5Password($data['password']);
        $this->data($data)->allowField(true)->save();
        $id = $this->id;

        $res = [
            'status' => true,
            'msg' => '注册成功',
            'data' => ['id' => $id],
        ];
        return $res;
    }

    /**
     * 更新注册用户信息
     * @Author   Laifuzi
     * @DateTime 2018-06-06
     * @param    array     $data 用户数据
     * @param    Boolean   $data 是否是管理员更新
     * @return   array
     */
    public function updateItem($data, $is_member = false)
    {
        $res = ['status' => false, 'msg' => '更新注册用户信息', 'data' => []];
        if(!isset($data['id'])){
            $res['msg'] = '更新用户不存在';
            return $res;
        }else if(!$is_member && $data['id'] != login_user_id()){
            $res['msg'] = '您没有权限更新该用户信息';
            return $res;
        }

        $validate = new Validate;
        $scene_name = 'update';
        if(isset($data['scene_name'])){
            $scene_name = $data['scene_name'];
        }
        if(!$validate->scene($scene_name)->check($data)){
            $res['msg'] = $validate->getError();
            return $res;
        }

        if(isset($data['password'])){
            if(empty($data['password'])){
                unset($data['password']);
            }else{
                $data['password'] = $this->md5Password($data['password']);
            }
        }
        $this->data($data)->isUpdate(true)->allowField(true)->save();

        $res = [
            'status' => true,
            'msg' => '更新用户信息成功',
            'data' => ['id' => $this->id],
        ];
        return $res;
    }

    /**
     * 查找或创建管理员记录
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-07
     * @param    array              $data [description]
     * @return   array                    [description]
     */
    public function findOrCreate($data)
    {
        $res = ['status' => false, 'data' => [], 'msg' => '查找或添加用户失败'];
        if(empty($data['mobile'])){
            $res['msg'] = '注册手机号码不能为空';
            return $res;
        }

        $item = $this->where('mobile', $data['mobile'])->find();
        if(!empty($item)){
            $res = [
                'status' => true,
                'data' => ['id' => $item['id']],
                'msg' => '查找到该注册会员',
            ];
            return $res;
        }
        return $this->createItem($data);
    }

    /**
     * 查询单条记录
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-22
     * @param    [type]             $id [description]
     * @return   [type]                 [description]
     */
    public function findOne($id){
        $select_fields = $this->findFields();
        $user = $this->field($select_fields)->where('id', $id)->find();
        if(empty($user)){
            return [];
        }

        unset($user['password']);
        return $user;
    }

    /**
     * 查询当前登录用户详细信息
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-25
     * @return   [type]             [description]
     */
    public function currentDetail(){
        $id = login_user_id();
        $select_fields = $this->findFields();
        $ext_fields = ['mobile', 'gender', 'birthday', 'college_name', 'pro_title'];
        foreach ($ext_fields as $key => $name) {
            array_push($select_fields, $name);
        }
        $user = $this->field($select_fields)->where('id', $id)->find();
        if(empty($user)){
            return [];
        }

        unset($user['password']);
        return $user;
    }

    /**
     * 登录方法
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-07
     * @param    string             $name     登录名
     * @param    string             $password 登录密码
     * @return   array
     */
    public function doLogin($name, $password){
        $res = ['status' => false, 'msg' => '登录失败', 'data' => []];
        if(empty($name)){
            $res['msg'] = '登录名不能为空';
            return $res;
        }

        $select_fields = $this->findFields();

        $map = [];
        $map[] = ['name|mobile', '=', $name];
        $item = $this->field($select_fields)->where($map)->find();
        if(empty($item)){
            $res['msg'] = '登录用户不存在';
            return $res;
        }else if($item['password'] != $this->md5Password($password)){
            $res['msg'] = '登录用户名或密码错误';
            return $res;
        }else if($item['status'] != true){
            $res['msg'] = '您的账号已被冻结';
            return $res;
        }
        // 返回结果里不包含密码
        unset($item['password']);

        $req = request();
        $data = ["last_login_ip" => ip2long($req->ip()), "last_login_time" => time()];
        $this->where('id', $item['id'])->update($data);
        return ['status' => true, 'msg' => '登录成功', 'data' => $item];
    }

    /**
    * 用户修改密码
    * @Author zhanghong
    * @Date   2016-12-22
    * @param  array         $data         密码信息
    * @param  array         $options      附加选项
    * @return [array]                     操作是否成功
    */
    public function changePassword($data, $only_active = true){
        $res = ["status" => false, "msg" => "密码更新失败"];

        // data包含 password(新密码), old_password(旧密码)，confirm_password(确认密码)
        $is_member = false;
        if(isset($options['is_member']) && $options['is_member']){
            $is_member = true;
        }
        if(!$is_member){
            // 如果不是管理员后台更新的话，登录用户只能修改自己的登录密码
            $data['id'] = login_user_id();
        }

        // 是否只允许更新status=1的用户
        $only_active = true;
        if(isset($options['only_active']) && $options['only_active'] == false){
            $only_active = false;
        }

        if(empty($data['id'])){
            $res['msg'] = '更新用户记录不存在';
            return $res;
        }
        $item = $this->where('id', $data['id'])->find();
        if(empty($item)){
            $res['msg'] = '未找到当前注册用户';
            return $res;
        }else if($only_active && $item['status'] != true){
            $res['msg'] = '已冻结用户不能修改密码';
            return $res;
        }else if($item['password'] != $this->md5Password($data["old_password"])){
            $res['msg'] = "旧密码错误";
            return $res;
        }

        // 过滤掉更新密码时不可以修改的字段
        $update_data = ['scene_name' => 'change_password'];
        $allow_fields = ['id', 'password', 'confirm_password'];
        foreach ($allow_fields as $key => $name) {
            if(isset($data[$name])){
                $update_data[$name] = $data[$name];
            }
        }

        return $this->updateItem($update_data, $is_member);
    }

    /**
     * 用户忘记密码，重置密码
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-27
     * @param    string             $mobile   [description]
     * @param    string             $password [description]
     * @return   array                        [description]
     */
    public function resetPassword($mobile, $password){
        $res = ['status' => false, 'msg' => '重置密码失败'];
        if(empty($mobile)){
            $res['msg'] = '注册手机号码不能为空';
            return $res;
        }

        $user = $this->where('status', true)->where('mobile', $mobile)->find();
        if(empty($user)){
            $res['msg'] = '您输入的手机号码还没有注册';
            return $res;
        }
        $data = [
            'id' => $user['id'],
            'password' => $password,
            'confirm_password' => $password,
        ];
        $res = $this->updateItem($data, true);
        return $res;
    }

    /**
     * 重新加载登录信息
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-07
     * @param    string             $name     登录名
     * @param    string             $password 登录密码
     * @return   boolean
     */
    public function reloadLoginInfo($id){
        $select_fields = $this->findFields();

        $user = $this->field($select_fields)->where('status', 1)->where('id', $id)->find();
        if(!empty($user)){
            unset($user['password']);
        }
        Session::set("user", $user);
        return true;
    }

    /**
    * 验证用户登录密码
    * @Author zhanghong
    * @Date   2017-01-01
    * @param  integer    $id       用户ID
    * @param  string     $password 登录密码
    * @return string               true/false
    */
    public function validPassword($id, $password){
        $item = $this->where("id", $id)->find();
        if(empty($item)){
            return 'false';
        }else if($item['status'] < 1){
            return 'false';
        }else if($item['password'] != $this->md5Password($password)){
            return 'false';
        }
        return "true";
    }

    /**
     * 唯一值字段列表
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-07
     * @return   array             [description]
     */
    protected function uniqueFileList()
    {
        return ['name', 'email', 'mobile'];
    }

    /**
     * 搜索排序方式
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-07
     * @param    string             $param 排序方式
     * @return   string                    [description]
     */
    protected function queryOrderStr($order_type = '')
    {
        return 'id DESC';
    }

    /**
     * 查询单条记录时查询的字段列表
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-22
     * @return   [type]             [description]
     */
    private function findFields(){
        return [
            'id', 'name', 'nickname', 'password', 'mobile', 'email',
            'avatar', 'status', 'create_time', 'update_time', 'status',
            'INET_NTOA(last_login_ip) AS last_login_ip',
            "FROM_UNIXTIME(last_login_time, '%Y-%m-%d %H:%i') AS last_login_time"
        ];
    }

    /**
     * 生成密码加密结果
     * @Author   Laifuzi
     * @DateTime 2018-06-06
     * @param    string     $password 用户输入密码
     * @param    string     $authcode 加密key
     * @return   string               加密后的密码
     */
    private function md5Password($password, $authcode = '')
    {
        if(empty($authcode)){
            $authcode = Config::get('app.authcode');
        }
        $result = "###".md5(md5($authcode.$password));
        return $result;
    }

    private function parseSearchParam($param)
    {
        $map = [];
        foreach ($param as $key => $value) {
            if(!is_array($value)){
                $value = trim($value);
            }
            switch ($key) {
            case "keyword":
                if(empty($value)){
                    continue;
                }else{
                    $keyword = "%{$value}%";
                }
                $map[] = ["name|nickname|email|mobile", "like", $keyword];
                break;
            }
        }
        return $map;
    }

    /**
     * 导出字段列表
     * @Author   zhanghong(Laifuzi)
     * @DateTime 2018-06-21
     * @return   [type]             [description]
     */
    private function exportHeaders(){
        return [
            ['name' => 'id', 'title' => '用户ID', 'type' => 'string', 'default' => ''],
            ['name' => 'name', 'title' => '登录名', 'type' => 'string', 'default' => ''],
            ['name' => 'mobile', 'title' => '注册手机', 'type' => 'string', 'default' => ''],
            // 使用switch开关，所以默认值必须是false，因为switch为关闭状态时返回的值里没有该字段
            ['name' => 'status', 'title' => '启用状态', 'type' => 'boolean', 'default' => false],
            ['name' => 'last_login_time', 'title' => '上次登录时间', 'type' => 'date', 'default' => ''],
            ['name' => 'last_ip', 'title' => '上次登录IP', 'type' => 'string', 'default' => ''],
            ['name' => 'create_time', 'title' => '注册时间', 'type' => 'date', 'default' => ''],
        ];
    }
}